package br.cin.stadium.middleware.marshall;

import java.util.ArrayList;

import br.cin.stadium.middleware.network.BufferStream;
import br.cin.stadium.middleware.network.DataInputStream;
import br.cin.stadium.middleware.network.DataOutputStream;

/**
 * 
 * Contains static methods allowing marshall/unmarshall operations. 
 * 
 * @author Jorge, Fabiano, Rafael, Vando
 * 
 */
public class Marshaller {

	/**
	 * Executes marshall according Serializable object. Each object is responsible to 
	 * to its conversion (GRASP pattern).
	 * 
	 * @param obj - Interface serializable
	 * @return Unstructed data.
	 */
	public static byte[] marshall(Serializable obj) {

		MarshallOutputStream mos = new DataOutputStream();

		try {
			obj.marshal(mos);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return mos.getData();
	}

	public static void marshall(Serializable obj, BufferStream stream) {

		MarshallOutputStream mos = new DataOutputStream(stream);

		try {
			obj.marshal(mos);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Executes UNmarshall according Serializable object. Each object is responsible to 
	 * to its conversion (GRASP pattern).
	 * <br>
	 * Object attributes is set.
	 * <br>
	 * 
	 * @param obj - Unstructed data
	 */
	public static void unmarshall(Serializable obj, byte[] data) {

		MarshallInputStream mis = new DataInputStream(data);

		try {
			obj.unmarshal(mis);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void unmarshall(Serializable obj, BufferStream stream) {

		MarshallInputStream mis = new DataInputStream(stream);

		try {
			obj.unmarshal(mis);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Executes marshall for a set of elements according Serializable object. Each object is responsible to 
	 * to its conversion (GRASP pattern).
	 * 
	 * @param obj - A set of structed data
	 * @return UNstructed data.
	 */
	public static byte[] marshall(Serializable[] objs) {

		MarshallOutputStream mos = new DataOutputStream();

		try {
			mos.writeInt(objs.length);
			
			for (int i = 0; i < objs.length; i++) {
				objs[i].marshal(mos);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return mos.getData();
	}

	 /**
     * Executes marshall for a set of elements according Serializable object. Each object is responsible to 
     * to its conversion (GRASP pattern).
     * 
     * @param obj - A set of structed data
     * @return UNstructed data.
     */
    public static byte[] marshall(ArrayList objs) {

            MarshallOutputStream mos = new DataOutputStream();

            try {
            	mos.writeInt(objs.size());
                for (int i = 0; i < objs.size(); i++) {
                        ((Serializable) objs.get(i)).marshal(mos);
                }
                
            } catch (Exception e) {
                    e.printStackTrace();
            }
            return mos.getData();
    }


    /**
     * Executes UNmarshall for a set of elements according Serializable object. Each object is responsible to 
     * to its conversion (GRASP pattern).
     * <br>
     * Object attributes is set for each obj in the unstructed data.
     * <br>
     * 
     * @param obj - Unstructed data
     */
    public static void unmarshall(Serializable obj, ArrayList objs, byte[] data) {
            MarshallInputStream mis = new DataInputStream(data);
            Class classDefinition = obj.getClass();
            
            try {
                int size = mis.readInt();
                
                for (int i = 0; i < size; i++) {
                    obj.unmarshal(mis);
                    objs.add(obj);
                    obj = (Serializable) classDefinition.newInstance();					
				}

            } catch (Exception e) {
                    e.printStackTrace();
            }
    }

}